﻿using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace AGE
{
    public class Transform
    {
        #region Properties
        //The 3D Vector that stores position
        private Vector3 v_translation;

        private Matrix worldMatrix;

        private Matrix parentMatrix;
        //The 3D Vector that stores scale
        private Vector3 v_scale;

        private Matrix m_rotation;

        private Entity entity;
        #endregion

        #region Accessors and Mutators for properties
        public Vector3 Position
        {
            get 
            {
                if (entity.IsChild)
                {
                    return v_translation + entity.Parent.Transform.Position;
                }
                else
                {
                    return v_translation;
                }
            }

            set
            {
                v_translation = value;
            }
        }

        public Matrix GetRotationMatrix()
        {
            return m_rotation;
        }


        public void Rotate(Vector3 axis, float degrees)
        {
            m_rotation = Matrix.CreateFromAxisAngle(axis, MathHelper.ToRadians(degrees)) * m_rotation;
        }

        public Vector3 Scale
        {
            get { return v_scale; }
            set { v_scale = value; }
        }
        #endregion

        public void TransformIntoWorld()
        {
            Quaternion rotation;
            worldMatrix = Matrix.CreateScale(v_scale) * m_rotation * Matrix.CreateTranslation(v_translation);
            parentMatrix = this.entity.Parent.Transform.GetWorldMatrix();
            Matrix transformedMatrix = parentMatrix * worldMatrix;
            transformedMatrix.Decompose(out v_scale, out rotation, out v_translation);
            m_rotation = Matrix.CreateFromQuaternion(rotation);
        }

        public Vector3 WorldPosition()
        {
            return GetWorldMatrix().Translation;
        }

        #region Main class function to retrieve a matrix based on transform properties
        public Matrix GetWorldMatrix()
        {
            if (this.entity.IsChild)
            {
                //Create three Matrices based on Scale, Rotation and Translation; multiply those three matrices, in that order.
                worldMatrix = Matrix.CreateScale(v_scale) * m_rotation * Matrix.CreateTranslation(v_translation);
                parentMatrix = this.entity.Parent.Transform.GetWorldMatrix();
                
                return worldMatrix * parentMatrix;
            }
            else
            {
                //Create three Matrices based on Scale, Rotation and Translation; multiply those three matrices, in that order.
                worldMatrix =  Matrix.CreateScale(v_scale) * m_rotation * Matrix.CreateTranslation(v_translation);
                return worldMatrix;
            }
        }
        #endregion

        public Transform(Entity parent)
        {
            this.entity = parent;
            Initialize();
        }

        public Transform(Entity parent, Vector3 translation, Vector3 rotation, Vector3 scale)
        {
            this.entity = parent;
            v_translation = translation;
            m_rotation *=
                Matrix.CreateFromAxisAngle(Vector3.Right, rotation.X) *
                Matrix.CreateFromAxisAngle(Vector3.Up, rotation.Y) *
                Matrix.CreateFromAxisAngle(Vector3.Backward, rotation.Z);
            v_scale = scale;
        }

        public void Translate(Vector3 translation)
        {
            v_translation += translation;
        }

        public void Translate(float x, float y, float z)
        {
            Translate(new Vector3(x, y, z));
        }

        public void Initialize()
        {
            v_translation = new Vector3(0.0f, 0.0f, 0.0f);
            m_rotation = Matrix.Identity;
            v_scale = new Vector3(1.0f, 1.0f, 1.0f);
        }
    }
}